package com.southsmart.springboot.smartdoc.api;

import lombok.Getter;
import lombok.Setter;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

/**
 * 统一返回格式
 *
 * @param <T> the type parameter
 * @author ziv
 * @version V1.0
 * @since 2021 -05-07 16:29:04
 */
@Getter
@Setter
public class Result<T> implements  Serializable {

    /**
     * The constant serialVersionUID.
     */
    private static final long serialVersionUID = 1L;

    /**
     * 操作是否成功
     */
    private boolean success;

    /**
     * 返回码
     */
    private String code;

    /**
     * 提示信息
     */
    private String msg;

    /**
     * 业务信息
     */
    private T data;

    /**
     * 业务信息，可使用add方法链式拼接数据
     */
    Map<String, Object> extend;

    /**
     * 增加日志
     *
     * @param value 日志信息
     * @return Result result
     */
    public Result<T> addLog(Object value) {
        return add("log", value);
    }

    /**
     * 增加业务信息
     *
     * @param key   业务信息key
     * @param value 业务信息
     * @return Result result
     */
    public Result<T> add(String key, Object value) {
        if (null == getExtend()) {
            setExtend(new HashMap<>());
        }
        this.getExtend().put(key, value);
        return this;
    }

    /**
     * 实例化
     *
     * @param resultCode the result code
     */
    public Result(ResponseCode resultCode) {
        this.success = resultCode.success();
        this.code = resultCode.getCode();
        this.msg = resultCode.getMsg();
    }

    /**
     * 返回错误
     *
     * @param <T> the type parameter
     * @return the result
     */
    public static <T> Result<T> failed() {
        return restResult(CommonCode.FAILED.success(), CommonCode.FAILED.getCode(), CommonCode.FAILED.getMsg(), null);
    }

    /**
     * Failed result.
     *
     * @param <T> the type parameter
     * @param msg the msg
     * @return the result
     */
    public static <T> Result<T> failed(String msg) {
        return restResult(CommonCode.FAILED.success(), CommonCode.FAILED.getCode(), msg, null);
    }

    /**
     * Failed result.
     *
     * @param <T>        the type parameter
     * @param resultCode the result code
     * @return the result
     */
    public static <T> Result<T> failed(ResponseCode resultCode) {
        return restResult(resultCode.success(), resultCode.getCode(), resultCode.getMsg(), null);
    }

    /**
     * Failed result.
     *
     * @param <T>        the type parameter
     * @param resultCode the result code
     * @param data       the data
     * @return the result
     */
    public static <T> Result<T> failed(ResponseCode resultCode, T data) {
        return restResult(resultCode.success(), resultCode.getCode(), resultCode.getMsg(), data);
    }

    /**
     * Ok result.
     *
     * @param <T> the type parameter
     * @return the result
     */
    public static <T> Result<T> ok() {
        return restResult(CommonCode.SUCCESS.success(), CommonCode.SUCCESS.getCode(), CommonCode.SUCCESS.getMsg(), null);
    }

    /**
     * Ok result.
     *
     * @param <T>  the type parameter
     * @param data the data
     * @return the result
     */
    public static <T> Result<T> ok(T data) {
        return restResult(CommonCode.SUCCESS.success(), CommonCode.SUCCESS.getCode(), CommonCode.SUCCESS.getMsg(), data);
    }

    /**
     * Ok result.
     *
     * @param <T>  the type parameter
     * @param data the data
     * @param msg  the msg
     * @return the result
     */
    public static <T> Result<T> ok(T data, String msg) {
        return restResult(CommonCode.SUCCESS.success(), CommonCode.SUCCESS.getCode(), msg, data);
    }

    /**
     * Rest result result.
     *
     * @param <T>     the type parameter
     * @param success the success
     * @param code    the code
     * @param msg     the msg
     * @param data    the data
     * @return the result
     */
    private static <T> Result<T> restResult(boolean success, String code, String msg, T data) {
        return new Result<>(success, code, msg, data);
    }

    /**
     * Instantiates a new Result.
     */
    public Result() {

    }

    /**
     * Instantiates a new Result.
     *
     * @param success the success
     * @param code    the code
     * @param msg     the msg
     * @param data    the data
     */
    public Result(boolean success, String code, String msg, T data) {
        this.success = success;
        this.code = code;
        this.msg = msg;
        this.data = data;
    }
}